package io.itit.ecp.admin.provide.action.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import icu.mhb.mybatisplus.plugln.extend.Joins;
import io.itit.ecp.admin.provide.action.req.SceneRoomQueryReq;
import io.itit.ecp.admin.provide.action.req.SceneRoomReq;
import io.itit.ecp.admin.provide.action.resp.DeviceResp;
import io.itit.ecp.admin.provide.action.resp.SceneRoomDeviceResp;
import io.itit.ecp.admin.provide.action.resp.SceneRoomResp;
import io.itit.ecp.admin.provide.helper.SceneHelper;
import io.itit.ecp.admin.provide.renderer.SceneRoomRenderer;
import io.itit.ecp.admin.server.entity.*;
import io.itit.ecp.admin.server.service.ISceneEdificeService;
import io.itit.ecp.admin.server.service.ISceneFloorService;
import io.itit.ecp.admin.server.service.ISceneProjectService;
import io.itit.ecp.admin.server.service.ISceneRoomService;
import io.itit.grass.common.exception.GrassException;
import io.itit.grass.common.provide.action.req.BaseBatchIdReq;
import io.itit.grass.common.provide.action.req.BaseIdReq;
import io.itit.grass.common.provide.action.resp.ResultResp;
import io.itit.grass.common.provide.action.validation.*;
import io.itit.grass.common.server.utils.ConvertUtils;
import io.itit.grass.estelle.starter.core.ExcelXSSFUtil;
import io.itit.grass.estelle.starter.parse.ExcelParseManage;
import io.itit.grass.estelle.starter.util.JsonUtil;
import io.itit.grass.web.wall.utils.PageUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * @Author：Roy
 * @Description：空间控制类
 * @Date：Create by 2023-11-23 10:29:25
 */
@Api(tags = "空间管理")
@RestController
@RequestMapping("/ecp-admin/sceneRoom")
public class SceneRoomController {

    @Resource
    private ISceneEdificeService sceneEdificeService;

    @Resource
    private ISceneRoomService sceneRoomService;

    @Resource
    private ISceneProjectService sceneProjectService;

    @Resource
    private ISceneFloorService sceneFloorService;


    @ApiOperation("分页查询")
    @PostMapping("queryPage")
    @RequiresPermissions("ecp-admin:sceneRoom:search")
    public ResultResp<IPage<SceneRoomResp>> queryPage(@RequestBody @Validated(IQueryPage.class) SceneRoomQueryReq req) {
        Page<SceneRoomResp> page = buildQW(req).joinPage(PageUtils.getPage(req, SceneRoomResp.class), SceneRoomResp.class);
        return ResultResp.success(page);
    }

    @ApiOperation("树查询")
    @PostMapping("queryTree")
    public ResultResp<List<Map<String, Object>>> queryTree(@RequestBody SceneRoomQueryReq req) {
        List<SceneProjectEntity> projectList = sceneProjectService.lambdaQuery().orderByDesc(SceneProjectEntity::getCreateTm).list();
        List<SceneEdificeEntity> edificeEntities = sceneEdificeService.lambdaQuery().orderByAsc(SceneEdificeEntity::getEdificeName).list();
        List<SceneFloorEntity> floorList = sceneFloorService.lambdaQuery().orderByAsc(SceneFloorEntity::getFloorNum).list();
        List<SceneRoomEntity> roomList = buildQW(req).joinList(SceneRoomEntity.class);
        List<Map<String, Object>> result = new ArrayList<>(projectList.size());
        Map<String, List<SceneEdificeEntity>> projectMap = edificeEntities.stream()
                .collect(Collectors.groupingBy(SceneEdificeEntity::getSceneProjectId));

        Map<String, List<SceneFloorEntity>> floorMap = floorList.stream()
                .collect(Collectors.groupingBy(SceneFloorEntity::getSceneEdificeId));
        Map<String, List<SceneRoomEntity>> roomMap = roomList.stream()
                .collect(Collectors.groupingBy(SceneRoomEntity::getSceneFloorId));
        for (SceneProjectEntity item : projectList) {
            Map<String, Object> m = new HashMap<>();
            m.put("id", item.getId());
            m.put("label", item.getProjectName());
            m.put("type", 1);
            m.put("children", projectMap.getOrDefault(item.getId(), Collections.emptyList()).stream().map(edifice -> {
                Map<String, Object> edificeMap = new HashMap<>();
                edificeMap.put("id", edifice.getId());
                edificeMap.put("label", edifice.getEdificeName());
                edificeMap.put("type", 2);
                edificeMap.put("children", floorMap.getOrDefault(edifice.getId(), Collections.emptyList()).stream().map(floor -> {
                    Map<String, Object> fMap = new HashMap<>();
                    fMap.put("id", floor.getId());
                    fMap.put("label", floor.getFloorName());
                    fMap.put("type", 3);
                    fMap.put("children", roomMap.getOrDefault(floor.getId(), Collections.emptyList()).stream().map(room -> {
                        Map<String, Object> rMap = new HashMap<>();
                        rMap.put("id", room.getId());
                        rMap.put("label", room.getRoomName());
                        rMap.put("type", 4);
                        return rMap;
                    }).collect(Collectors.toList()));
                    return fMap;
                }).collect(Collectors.toList()));
                return edificeMap;
            }).collect(Collectors.toList()));
            result.add(m);
        }
        return ResultResp.success(result);
    }

    @ApiOperation("查询全部")
    @PostMapping("queryList")
    public ResultResp<List<SceneRoomResp>> queryList(@RequestBody SceneRoomQueryReq req) {
        List<SceneRoomResp> list = Joins.of(SceneProjectEntity.class)
                .selectAs(t -> t.addFunAlias(SceneProjectEntity::getId, SceneRoomResp::getSceneProjectId)
                        .addFunAlias(SceneProjectEntity::getProjectName, SceneRoomResp::getProjectName))

                .leftJoin(SceneEdificeEntity.class, SceneEdificeEntity::getSceneProjectId, SceneProjectEntity::getId)
                .selectAs(t -> t.addFunAlias(SceneEdificeEntity::getId, SceneRoomResp::getSceneEdificeId)
                        .addFunAlias(SceneEdificeEntity::getEdificeName, SceneRoomResp::getEdificeName))
                .orderByAsc(SceneEdificeEntity::getEdificeName)
                .end()

                .leftJoin(SceneFloorEntity.class, SceneFloorEntity::getSceneEdificeId, SceneEdificeEntity::getId)
                .selectAs(t -> t.addFunAlias(SceneFloorEntity::getId, SceneRoomResp::getSceneFloorId)
                        .addFunAlias(SceneFloorEntity::getFloorName, SceneRoomResp::getFloorName))
                .orderByAsc(SceneFloorEntity::getFloorNum)
                .end()

                .leftJoin(SceneRoomEntity.class, SceneRoomEntity::getSceneFloorId, SceneFloorEntity::getId)
                .selectAs(t -> t.addFunAlias(SceneRoomEntity::getId, SceneRoomResp::getId)
                        .addFunAlias(SceneRoomEntity::getRoomName, SceneRoomResp::getRoomName))

                .isNull(req.getNullCompanyId() != null, SceneRoomEntity::getSceneCompanyId)
                .eq(StringUtils.isNotEmpty(req.getId()), SceneRoomEntity::getId, req.getId())
                .eq(StringUtils.isNotEmpty(req.getSceneEdificeId()), SceneRoomEntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(StringUtils.isNotEmpty(req.getSceneFloorId()), SceneRoomEntity::getSceneFloorId, req.getSceneFloorId())
                .eq(StringUtils.isNotEmpty(req.getSceneCompanyId()), SceneRoomEntity::getSceneCompanyId, req.getSceneCompanyId())
                .like(StringUtils.isNotEmpty(req.getRoomName()), SceneRoomEntity::getRoomName, req.getRoomName())
                .eq(req.getRoomArea() != null, SceneRoomEntity::getRoomArea, req.getRoomArea())
                .eq(StringUtils.isNotEmpty(req.getDeptId()), SceneRoomEntity::getDeptId, req.getDeptId())
                .in(CollectionUtils.isNotEmpty(req.getIds()), SceneRoomEntity::getId, req.getIds())
                .orderByAsc(SceneRoomEntity::getRoomName)
                .end()
                .eq(StringUtils.isNotEmpty(req.getSceneProjectId()), SceneProjectEntity::getId, req.getSceneProjectId())
                .orderByAsc(SceneProjectEntity::getProjectName)
                .joinList(SceneRoomResp.class);

        List<SceneRoomResp> collect = list.stream().map((item) -> {
            if (item.getRoomName() != null) {
                SceneRoomEntity room = sceneRoomService.lambdaQuery()
                        .eq(item.getSceneEdificeId() != null, SceneRoomEntity::getSceneEdificeId, item.getSceneEdificeId())
                        .eq(item.getRoomName() != null, SceneRoomEntity::getRoomName, item.getRoomName())
                        .eq(StringUtils.isNotEmpty(item.getSceneFloorId()), SceneRoomEntity::getSceneFloorId, item.getSceneFloorId())
                        .one();
                item.setRoomArea(room.getRoomArea());
            }
            return item;
        }).collect(Collectors.toList());

        return ResultResp.success(collect);
    }

    @ApiOperation("详情")
    @PostMapping("detail")
    @RequiresPermissions("ecp-admin:sceneRoom:search")
    public ResultResp<SceneRoomResp> detail(@RequestBody @Validated(IRequired.class) BaseIdReq req) {
        return ResultResp.success(ConvertUtils.copy(sceneRoomService.getById(req.getId()), SceneRoomResp.class));
    }

    @ApiOperation("详情")
    @GetMapping("queryRoomDetail")
    public ResultResp<SceneRoomDeviceResp> queryRoomDetail(@RequestParam String id) {
        SceneRoomDeviceResp deviceResp = Joins.of(SceneRoomEntity.class)
                .selectAll()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, SceneRoomEntity::getSceneProjectId)
                .selectAs(SceneProjectEntity::getProjectName, SceneRoomDeviceResp::getProjectName)
                .end()
                .leftJoin(SceneEdificeEntity.class, SceneEdificeEntity::getId, SceneRoomEntity::getSceneEdificeId)
                .selectAs(SceneEdificeEntity::getEdificeName, SceneRoomDeviceResp::getEdificeName)
                .end()
                .leftJoin(SceneFloorEntity.class, SceneFloorEntity::getId, SceneRoomEntity::getSceneFloorId)
                .selectAs(SceneFloorEntity::getFloorName, SceneRoomDeviceResp::getFloorName)
                .end()
                .leftJoin(SceneCompanyEntity.class, SceneCompanyEntity::getId, SceneRoomEntity::getSceneCompanyId)
                .selectAs(SceneCompanyEntity::getCompanyName, SceneRoomDeviceResp::getCompanyName)
                .end()
                .eq(SceneRoomEntity::getId, id)
                .joinGetOne(SceneRoomDeviceResp.class);

        List<DeviceResp> deviceResps = Joins.of(DeviceEntity.class)
                .selectAll()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, DeviceEntity::getSceneProjectId)
                .selectAs(SceneProjectEntity::getProjectName, DeviceResp::getProjectName)
                .end()
                .leftJoin(ProductTypeEntity.class, ProductTypeEntity::getId, DeviceEntity::getProductTypeId)
                .selectAs(ProductTypeEntity::getProductTypeName, DeviceResp::getProductTypeName)
                .end()
                .eq(DeviceEntity::getSceneRoomId, id)
                .joinList(DeviceResp.class);
        deviceResps = SceneHelper.i().setSceneInfo(deviceResps);
        deviceResp.setDevices(deviceResps);
        return ResultResp.success(deviceResp);
    }

    /**
     * 组装查询条件
     *
     * @param req
     * @return
     */
    private static JoinLambdaWrapper<SceneRoomEntity> buildQW(SceneRoomQueryReq req) {
        return Joins.of(SceneRoomEntity.class)
                .selectAll()
                .leftJoin(SceneProjectEntity.class, SceneProjectEntity::getId, SceneRoomEntity::getSceneProjectId)
                .select(SceneProjectEntity::getProjectName)
                .end()
                .leftJoin(SceneEdificeEntity.class, SceneEdificeEntity::getId, SceneRoomEntity::getSceneEdificeId)
                .like(StringUtils.isNotEmpty(req.getEdificeName()), SceneEdificeEntity::getEdificeName, req.getEdificeName())
                .select(SceneEdificeEntity::getEdificeName)
                .end()
                .leftJoin(SceneFloorEntity.class, SceneFloorEntity::getId, SceneRoomEntity::getSceneFloorId)
                .select(SceneFloorEntity::getFloorName)
                .end()
                .leftJoin(SceneCompanyEntity.class, SceneCompanyEntity::getId, SceneRoomEntity::getSceneCompanyId)
                .select(SceneCompanyEntity::getCompanyName)
                .end()
                .isNull(req.getNullCompanyId() != null, SceneRoomEntity::getSceneCompanyId)
                .eq(StringUtils.isNotEmpty(req.getSceneProjectId()), SceneRoomEntity::getSceneProjectId, req.getSceneProjectId())
                .eq(StringUtils.isNotEmpty(req.getId()), SceneRoomEntity::getId, req.getId())
                .eq(StringUtils.isNotEmpty(req.getSceneEdificeId()), SceneRoomEntity::getSceneEdificeId, req.getSceneEdificeId())
                .eq(StringUtils.isNotEmpty(req.getSceneFloorId()), SceneRoomEntity::getSceneFloorId, req.getSceneFloorId())
                .eq(StringUtils.isNotEmpty(req.getSceneCompanyId()), SceneRoomEntity::getSceneCompanyId, req.getSceneCompanyId())
                .like(StringUtils.isNotEmpty(req.getRoomName()), SceneRoomEntity::getRoomName, req.getRoomName())
                .eq(req.getRoomArea() != null, SceneRoomEntity::getRoomArea, req.getRoomArea())
                .eq(StringUtils.isNotEmpty(req.getDeptId()), SceneRoomEntity::getDeptId, req.getDeptId())
                .in(CollectionUtils.isNotEmpty(req.getIds()), SceneRoomEntity::getId, req.getIds())
                .last(StringUtils.isNotEmpty(req.getSortColumn()), PageUtils.lastOrderBy(req))
                .orderByAsc(SceneRoomEntity::getRoomName);
    }

    @ApiOperation("新增")
    @PostMapping("add")
    @RequiresPermissions("ecp-admin:sceneRoom:add")
    public ResultResp<Boolean> add(@RequestBody @Validated({IAdd.class}) SceneRoomReq req) {
        checkDataExists(req);
        return ResultResp.success(sceneRoomService.save(ConvertUtils.convertIgnoreId(req, SceneRoomEntity.class)));
    }

    @ApiOperation("编辑")
    @PostMapping("update")
    @RequiresPermissions("ecp-admin:sceneRoom:update")
    public ResultResp<Boolean> update(@RequestBody @Validated({IUpdate.class}) SceneRoomReq req) {
        checkDataExists(req);
        return ResultResp.success(sceneRoomService.updateById(ConvertUtils.copy(req, SceneRoomEntity.class)));
    }

    private void checkDataExists(SceneRoomReq req) {
        Long count = sceneRoomService.lambdaQuery()
                .eq(SceneRoomEntity::getSceneFloorId, req.getSceneFloorId())
                .eq(SceneRoomEntity::getRoomName, req.getRoomName())
                .ne(StringUtils.isNotEmpty(req.getId()), SceneRoomEntity::getId, req.getId())
                .count();
        GrassException.throwEx(count > 0, "空间名称已存在！");
    }

    @ApiOperation("删除(根据Id删)")
    @PostMapping("deleteById")
    @RequiresPermissions("ecp-admin:sceneRoom:deleteById")
    public ResultResp<Boolean> deleteById(@RequestBody @Validated({IRequired.class}) BaseIdReq req) {
        return ResultResp.success(sceneRoomService.removeRooms(Collections.singletonList(req.getId())));
    }

    @ApiOperation("批量删除")
    @PostMapping("batchDelete")
    @RequiresPermissions("ecp-admin:sceneRoom:batchDelete")
    public ResultResp<Boolean> batchDelete(@RequestBody @Validated({IRequired.class}) BaseBatchIdReq req) {
        return ResultResp.success(sceneRoomService.removeRooms(req.getIds()));
    }

    @ApiOperation("导入")
    @PostMapping("upload")
    @RequiresPermissions("ecp-admin:sceneRoom:upload")
    public ResultResp<Integer> upload(@RequestParam("file") MultipartFile file, Boolean ignoreError) {
        return ResultResp.success(ExcelParseManage.i().process(SceneRoomRenderer.ENTITY_NAME, file, ignoreError));
    }

    @ApiOperation("导出")
    @PostMapping("export")
    @RequiresPermissions("ecp-admin:sceneRoom:export")
    public void export(@RequestBody @Validated(IExport.class) SceneRoomQueryReq req, HttpServletResponse response) {
        ExcelXSSFUtil.export("SceneRoomExport", JsonUtil.toJson(buildQW(req).joinList(SceneRoomResp.class)), response);
    }

    @ApiOperation("通过楼栋Id / 楼层Id / 空间Id 获取所属场景")
    @PostMapping("querySceneInfo")
    public ResultResp<String> querySceneInfo(@RequestBody @Validated(IOther.class) SceneRoomQueryReq req) {
        return ResultResp.success(sceneEdificeService.getSceneInfoName(req.getSceneEdificeId(), req.getSceneFloorId(), req.getId()));
    }

}
